﻿using System;
using Linq.Utils;
using System.Linq;
using System.Data.Linq.SqlClient;

namespace MyForum.Business.Controllers
{
    public class UserController : GenericController<User, MyForumDataContext>
    {
        public static bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            #region Validation
            if (String.IsNullOrEmpty(username))
            {
                throw new ArgumentNullException("username");
            }

            if (String.IsNullOrEmpty(oldPassword))
            {
                throw new ArgumentNullException("oldPassword");
            }

            if (String.IsNullOrEmpty(newPassword))
            {
                throw new ArgumentNullException("newPassword");
            }
            #endregion

            User user = GetUser(username);

            if (user == null)
            {
                return false;
            }

            if (oldPassword != user.Password)
            {
                return false;
            }
            
            user.Password = newPassword;
            Update(user);

            return true;
        }

        public static bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            #region Validation
            if (String.IsNullOrEmpty(username))
            {
                throw new ArgumentNullException("username");
            }

            if (String.IsNullOrEmpty(password))
            {
                throw new ArgumentNullException("password");
            }

            if (String.IsNullOrEmpty(newPasswordQuestion))
            {
                throw new ArgumentNullException("newPasswordQuestion");
            }

            if (String.IsNullOrEmpty(newPasswordAnswer))
            {
                throw new ArgumentNullException("newPasswordAnswer");
            }
            #endregion

            User user = GetUser(username);

            if (user == null)
            {
                return false;
            }

            if (password != user.Password)
            {
                return false;
            }
            
            user.PasswordQuestion = newPasswordQuestion;
            user.PasswordAnswer = newPasswordAnswer;
            Update(user);

            return true;
        }

        public static bool CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, DateTime creationDate)
        {
            #region Validation
            if (String.IsNullOrEmpty(username))
            {
                throw new ArgumentNullException("username");
            }

            if (String.IsNullOrEmpty(password))
            {
                throw new ArgumentNullException("password");
            }

            if (String.IsNullOrEmpty(email))
            {
                throw new ArgumentNullException("email");
            }
            #endregion

            User user = new User();

            user.Username = username;
            user.Password = password;
            user.Email = email;
            user.PasswordQuestion = passwordQuestion;
            user.PasswordAnswer = passwordAnswer;
            user.IsApproved = isApproved;
            user.CreationDate = creationDate;

            DataContext.Users.InsertOnSubmit(user);
            Insert(user);

            return true;
        }

        public static bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            #region Validation
            if (String.IsNullOrEmpty(username))
            {
                throw new ArgumentNullException("username");
            }
            #endregion

            User user = GetUser(username);

            if (user == null)
            {
                return false;
            }

            //TODO : what to do if deleteAllRelatedData?

            Delete(user);

            return true;
        }

        public static IQueryable<User> FindUsersByEmail(string emailToMatch, int pageSize, int pageIndex)
        {
            #region Validation
            if (pageSize <= 0)
            {
                throw new ArgumentOutOfRangeException("pageSize");
            }

            if (pageIndex < 0)
            {
                throw new ArgumentOutOfRangeException("pageIndex");
            }
            #endregion

            IQueryable<User> result = from user in DataContext.Users
                                      where SqlMethods.Like(user.Email, emailToMatch)
                                      select user;

            return result.Skip(pageIndex).Take(pageSize);
        }

        public static IQueryable<User> FindUsersByName(string usernameToMatch, int pageSize, int pageIndex)
        {
            #region Validation
            if (pageSize <= 0)
            {
                throw new ArgumentOutOfRangeException("pageSize");
            }

            if (pageIndex < 0)
            {
                throw new ArgumentOutOfRangeException("pageIndex");
            }
            #endregion

            IQueryable<User> result = from user in DataContext.Users
                                      where SqlMethods.Like(user.Username, usernameToMatch)
                                      select user;

            return result;
        }

        public static int GetNumberOfUsersOnline(DateTime compareTime)
        {
            int result = DataContext.Users.Count(user => user.IsOnline);

            return result;
        }

        public static string GetPassword(string username, string answer)
        {
            #region Validation
            if (String.IsNullOrEmpty(username))
            {
                throw new ArgumentNullException("username");
            }
            #endregion

            User user = GetUser(username);

            if (user == null)
            {
                return null;
            }

            if (answer != user.PasswordAnswer)
            {
                return null;
            }

            return user.Password;
        }

        public static User GetUser(string username)
        {
            #region Validation
            if (String.IsNullOrEmpty(username))
            {
                throw new ArgumentNullException("username");
            }
            #endregion

            User user = (from u in DataContext.Users
                        where u.Username == username
                        select u).SingleOrDefault();

            return user;
        }

        public static void UpdateUserActivity(User user)
        {
            #region Validation
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }
            #endregion

            if (user == null)
            {
                return;
            }

            user.LastActivityDate = DateTime.Now;
            Update(user);
        }

        public static bool Unlockuser(string username)
        {
            #region Validation
            if (String.IsNullOrEmpty(username))
            {
                throw new ArgumentNullException("username");
            }
            #endregion

            User user = GetUser(username);

            if (user == null)
            {
                return false;
            }

            user.IsLockedOut = false;
            user.LastLockedOutDate = DateTime.Now;
            Update(user);

            return true;
        }

        public static void UpdateLastLogin(User user)
        {
            #region Validation
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }
            #endregion

            if (user == null)
            {
                return;
            }

            user.LastLoginDate = DateTime.Now;
            Update(user);
        }

        public static string GetUserNameByEmail(string email)
        {
            #region Validation
            if (String.IsNullOrEmpty(email))
            {
                throw new ArgumentNullException("email");
            }
            #endregion

            string result = (from user in DataContext.Users
                            where user.Email == email
                            select user.Email).SingleOrDefault();

            return result;
        }

        public static bool ResetPassword(string username, string answer, string newPassword)
        {
            #region Validation
            if (String.IsNullOrEmpty(username))
            {
                throw new ArgumentNullException("username");
            }

            if (String.IsNullOrEmpty(newPassword))
            {
                throw new ArgumentNullException("newPassword");
            }
            #endregion

            User user = GetUser(username);

            if (user == null)
            {
                return false;
            }

            if (answer != user.PasswordAnswer)
            {
                return false;
            }

            user.Password = newPassword;
            Update(user);

            return true;
        }

        public static bool UpdateUser(string email, string comment, bool isApproved, string username)
        {
            #region Validation
            if (String.IsNullOrEmpty(username))
            {
                throw new ArgumentNullException("username");
            }
            #endregion

            User user = GetUser(username);

            if (user == null)
            {
                return false;
            }

            if (!String.IsNullOrEmpty(email))
            {
                user.Email = email;
            }

            if (!String.IsNullOrEmpty(comment))
            {
                user.Comment = comment;
            }

            user.IsApproved = isApproved;
            Update(user);

            return true;
        }
    }
}
